package com.liuche.homechat.common.common.service;

import com.liuche.homechat.common.common.exception.BusinessException;
import com.liuche.homechat.common.common.exception.CommonErrorEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @author：liuche
 * @Date：2024年06月02日 11:37
 * @Description：编程式分布式锁
 */
@Slf4j
@Service
public class LockService {
    @Resource
    private RedissonClient redissonClient;

    @SneakyThrows
    public <T> T tryLock(String key, int waitTime, TimeUnit timeUnit, SupplierThrow<T> supplier) {
        RLock lock = redissonClient.getLock(key);
        try {
            boolean lockFlag = lock.tryLock(waitTime, timeUnit);

            if (!lockFlag) {
                throw new BusinessException(CommonErrorEnum.FREQUENCY_LIMIT);
            }
            return supplier.get();
        } finally {
            lock.unlock();
        }
    }

    @SneakyThrows
    public <T> T tryLock(String key, SupplierThrow<T> supplier) {
        RLock lock = redissonClient.getLock(key);
        try {
            boolean lockFlag = lock.tryLock();

            if (!lockFlag) {
                throw new BusinessException(CommonErrorEnum.FREQUENCY_LIMIT);
            }
            return supplier.get();
        } finally {
            lock.unlock();
        }
    }

    @FunctionalInterface
    public interface SupplierThrow<T> {

        /**
         * Gets a result.
         *
         * @return a result
         */
        T get() throws Throwable;
    }
}
